package gu.sql2java.store;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 基于 {@link LocalBinaryStore} 支持多分区存储的{@link URLStore}实现
 * @author guyadong
 * @since 3.32.6
 */
public class MultiLocalStore extends BasesLocalBinaryStore {
	private final ConcurrentHashMap<String, LocalBinaryStore> stores = new ConcurrentHashMap<>();

	public MultiLocalStore(File storeRoot) {
		super(storeRoot);
	}
	
	public MultiLocalStore(String storeRoot) {
		super(storeRoot);
	}

	/**
	 * 增加存储分区
	 * @param partition 存储路径前缀(分区)
	 * @param level 存储目录级数,小于0或大于4则使用默认值2
	 */
	public void addPartition(String partition, int level) {
		addPartition(partition, new LocalBinaryStore(storeRoot, partition, level));
	}
	/**
	 * 增加 {@code partition} 指定的名字的分区
	 * @param partition 存储路径前缀(分区)
	 * @param localBinaryStore
	 */
	public void addPartition(String partition,LocalBinaryStore localBinaryStore) {
		if (null == partition || partition.length() == 0) {
			throw new IllegalArgumentException("partition is null or empty");
		}
		if (null == localBinaryStore) {
			throw new NullPointerException("localBinaryStore is null");
		}
		if (!Objects.equals(getStoreRoot(), localBinaryStore.getStoreRoot())) {
			throw new IllegalArgumentException(
					String.format("MISMATCH storeRoot %s VS %s", getStoreRoot(), localBinaryStore.getStoreRoot()));
		}
		stores.putIfAbsent(partition, localBinaryStore);
	}
	/**
	 * 返回指定前缀(分区)的存储实例
	 * @param partition 存储路径前缀(分区)
	 */
	public LocalBinaryStore getStore(String partition) {
		return stores.get(partition);
	}

	/**
	 * 保存数据到{@code partition}指定的分区
	 * @see #store(Object, String, String, boolean, boolean)
	 */
	public <T> URL store(String partition,  T binary, String md5, String extension, boolean overwrite, boolean makeURLOnly) throws IOException {
		LocalBinaryStore store = stores.get(partition);
		if (null == store) {
			throw new IllegalArgumentException("INVALID partition=" + partition);
		}
		return store.store(binary, md5, extension,overwrite, makeURLOnly);
	}

	@Override
	protected URL doStore(byte[] binary, String md5, String extension, boolean overwrite, boolean makeURLOnly) throws IOException {
		throw new UnsupportedOperationException("UNSUPPORTED method, replace with store(String,  Object, String, String, boolean, boolean)");
	}
	
	@Override
	protected URL doFind(String md5) {
		URL url;
		for (LocalBinaryStore store : stores.values()) {
			if ((url = store.doFind(md5)) != null) {
				return url;
			}
		}
		return null;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + Objects.hash(stores);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		MultiLocalStore other = (MultiLocalStore) obj;
		return Objects.equals(stores, other.stores);
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("MultiLocalStore [stores=").append(stores).append("]");
		return builder.toString();
	}

}
